package com.jh.fcsm.common.aspect;

import com.alibaba.fastjson2.JSONObject;
import com.jh.fcsm.beans.sys.SysLogRecord;
import com.jh.fcsm.beans.sys.vo.LoginUser;
import com.jh.fcsm.common.annotation.SystemLogAnnotation;
import com.jh.fcsm.service.sys.SysLogService;
import com.jh.fcsm.util.AppUserUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Component
@Aspect
public class SystemLogAop {

    private static final Logger logger = LoggerFactory.getLogger(SystemLogAop.class);
    @Autowired
    private SysLogService sysLogService;

    public static String getCurrentUserId() {
        Object user = AppUserUtil.getLoginAppUser();
        if (user instanceof LoginUser) {
            LoginUser appLoginUser = (LoginUser) user;
            return appLoginUser.getId();
        }
        return null;
    }

    public static String getCurrentUserName() {
        Object user = AppUserUtil.getLoginAppUser();
        if (user instanceof LoginUser) {
            LoginUser appLoginUser = (LoginUser) user;
            return appLoginUser.getUsername();
        }
        return null;
    }

    public static String getCurrentRealName() {
        Object user = AppUserUtil.getLoginAppUser();
        if (user instanceof LoginUser) {
            LoginUser appLoginUser = (LoginUser) user;
            return appLoginUser.getNickname();
        }
        return null;
    }

    /**
     * 环绕带注解 @SystemLogAnnotation的方法做aop
     */
    @Around(value = "@annotation(com.jh.fcsm.common.annotation.SystemLogAnnotation)")
    public Object logSave(ProceedingJoinPoint joinPoint) throws Throwable {

        SysLogRecord log = new SysLogRecord();
        log.setCreateTime(new Date());
        Long beginTime = System.currentTimeMillis();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        SystemLogAnnotation logAnnotation =
                methodSignature.getMethod().getDeclaredAnnotation(SystemLogAnnotation.class);
        log.setModule(logAnnotation.value());
        log.setModuleType(logAnnotation.type());
        try {
            // 取用户信息和请求路径
            HttpServletRequest request =
                    ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            log.setRemark("URL:" + request.getRequestURL().toString());
            log.setIp(getCurrentIp());
            LoginUser user = getCurrentUser(); // 获取用户信息
            if (user != null) {
                log.setCreateUser(user.getId());
                log.setCreateUserNickname(user.getNickname());
                log.setUserId(user.getUsername());
                log.setUserName(user.getNickname());
            }

        } catch (Exception e) {
        }
        if (logAnnotation.recordParam()) { // 是否要记录方法的参数数据
            String[] paramNames = methodSignature.getParameterNames();// 参数名
            if (paramNames != null && paramNames.length > 0) {
                Object[] args = joinPoint.getArgs();// 参数值

                Map<String, Object> params = new HashMap<>();
                for (int i = 0; i < paramNames.length; i++) {
                    Object value = args[i];
                    if (value instanceof Serializable) {
                        params.put(paramNames[i], value);
                    }
                }
                try {
                    log.setParams(JSONObject.toJSONString(params)); // 以json的形式记录参数
                } catch (Exception e) {
                    logger.error("记录参数失败：{}", e);
                }
            }
        }
        try {
            Object object = joinPoint.proceed();// 执行原方法
            log.setFlag(1);
            return object;
        } catch (Exception e) { // 方法执行失败
            log.setFlag(0);
            log.setRemark(log.getRemark() + "  " + e.getMessage()); // 备注记录失败原因
            throw e;
        } finally {
            // 异步将Log对象发送到队列
            CompletableFuture.runAsync(() -> {
                try {
                    Long endTime = System.currentTimeMillis();
                    log.setUseTimes(endTime - beginTime);
                    // 给MQ发送生产者信息
                    sysLogService.saveOrUpdateLogRecord(log);
                    logger.info("发送日志到队列：{}", log);
                } catch (Exception e2) {
                    logger.error("发送日志到队列：{}", e2);
                }
            });
        }
    }

    /**
     * 获取登录用户信息
     *
     * @return
     */
    private LoginUser getCurrentUser() {
        Object user = AppUserUtil.getLoginAppUser();
        if (user instanceof LoginUser) {
            LoginUser appLoginUser = (LoginUser) user;
            return appLoginUser;
        }
        return null;
    }

    private String getCurrentIp() {
        // 取用户信息和请求路径
        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
